#include <stdio.h>
#include "dominion.h"
#include "dominion_helpers.h"
#include <time.h>
#include <stdlib.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include "showGameState.h"
#include <stdbool.h>
#include "mySeaHag.h"
#include <string.h>
#include <assert.h>

// Globals
gsl_rng *rng;   //Random number generator, initialized in main


int randomRange(int a, int b)
{
    // Returns a random integer in the range [a, b]

    // return rand() % (b - a) + a;
    if (a < b)
    {
        return gsl_rng_uniform_int(rng, (b - a)) + a;
    }
    else
    {
        return 0;
    }
}


void chooseKingdomCards(enum CARD *chosenCards)
{
    // return 10 distinct randomly chosen Kingdom cards
    int i = 0;
    int num_kcards = treasure_map - adventurer + 1;
    enum CARD allKingdomCards[num_kcards];
    for (enum CARD c = adventurer; c <= treasure_map; c++ )
    {
        allKingdomCards[i++] = c;
    }

    gsl_ran_choose(rng, chosenCards, 10, allKingdomCards, num_kcards, sizeof(enum CARD));
}


void chooseCards(unsigned int k, enum CARD *chosenCards)
{
    // return n cards, not necessarily distinct
    int i = 0;
    int num_cards = treasure_map - curse + 1;
    enum CARD allCards[num_cards];
    for (enum CARD c = curse; c <= treasure_map; c++ )
    {
        allCards[i++] = c;
    }
    gsl_ran_sample(rng, chosenCards, k, allCards, num_cards, sizeof(enum CARD));
}


void setGameState(struct gameState *state)
{
    state->numPlayers = randomRange(2, MAX_PLAYERS);

    state->supplyCount[copper] = randomRange(0, 60 - 7 * state->numPlayers);
    state->supplyCount[silver] = randomRange(0,  40);
    state->supplyCount[gold]   = randomRange(0,  30);

    int victoryCardSupply = (state->numPlayers == 2) ? 8 : 12;
    for (enum CARD c = estate; c <= province; c++ )
    {
        state->supplyCount[c] = randomRange(0, victoryCardSupply);

    }
    int ncurses;
    switch (state->numPlayers)
    {
    case 2: ncurses =  randomRange(0, 10);
        break;
    case 3: ncurses =  randomRange(0, 20);
        break;
    case 4: ncurses =  randomRange(0, 30);
        break;
    };
    state->supplyCount[curse] = randomRange(0, ncurses);

    // Set supply count for all Kingdom cards to 0
    for (enum CARD c = adventurer; c <= treasure_map; c++ )
    {
        state->supplyCount[c] = 0;
    }
    // Choose 10 Kingdow cards to use in this game and set their counts to [0, 10]
    enum CARD kingdomCards[10];
    chooseKingdomCards(kingdomCards);
    for (int i = 0; i < 10; i++)
    {
        state->supplyCount[kingdomCards[i]] = randomRange(0, 10);
    }

    for (enum CARD c = estate; c <= province; c++ )
    {
        state->embargoTokens[c]   = 0;
    }

    state->outpostPlayed = 0;
    state->outpostTurn = 0;
    state->whoseTurn = randomRange(0, state->numPlayers);
    state->phase = 0;
    state->numActions = 1;
    state->coins = randomRange(0, 25);
    state->numBuys = 1;

    // Set hand count and hand to 0 for all players
    for (int p = 0; p < MAX_PLAYERS; ++p)
    {
        state->handCount[p] = 0;
    }

    for (int p = 0; p < MAX_PLAYERS; ++p)
    {
        for (int i = 0; i < MAX_HAND; ++i)
        {
            state->hand[p][i] = 0;
        }
    }

    // Set current players hand count to a random value
    // int handSize = randomRange(1, MAX_HAND);
    int handSize = randomRange(1, 25);

    state->handCount[state->whoseTurn] = handSize;
    // set current players hand to include random cards
    enum CARD hand_cards[handSize];
    chooseCards(handSize, hand_cards);
    for (int i = 0; i < handSize; ++i)
    {
        state->hand[state->whoseTurn][i] = hand_cards[i];
    }

    // Setup players decks
    for (int p = 0; p < MAX_PLAYERS; ++p)
    {
        // int deckSize = randomRange(0, MAX_DECK);
        int deckSize = randomRange(0, 25);
        state->deckCount[p] = deckSize;
        enum CARD deck_cards[deckSize];
        chooseCards(deckSize, deck_cards);
        for (int i = 0; i < deckSize; ++i)
        {
            state->deck[p][i] = deck_cards[i];
        }
    }

    // Setup players discard piles
    for (int p = 0; p < MAX_PLAYERS; ++p)
    {
        int discardSize = randomRange(0, 25);
        state->discardCount[p] = discardSize;
        enum CARD discard_cards[discardSize];
        chooseCards(discardSize, discard_cards);
        for (int i = 0; i < discardSize; ++i)
        {
            state->discard[p][i] = discard_cards[i];
        }
    }
    //played cards
    int playedSize = randomRange(0, 5);
    state->playedCardCount = playedSize;
    enum CARD played_cards[playedSize];
    chooseCards(playedSize, played_cards);
    for (int i = 0; i < playedSize; ++i)
    {
        state->playedCards[i] = played_cards[i];
    }
}

bool insertCard(enum CARD card, int posn, struct gameState *state)
{   // insert card into current player's hand
    if (posn < state->handCount[state->whoseTurn])
    {
        state->hand[state->whoseTurn][posn] = card;
        return true;
    }
    else
    {
        return false;
    }
}


int main(int argc, char const *argv[])
{
    // set up random number generator

    const gsl_rng_type *T;
    T = gsl_rng_mt19937;
    rng = gsl_rng_alloc(T);
    unsigned int seed = time(0);
    gsl_rng_set(rng, seed);


    struct gameState *state;
    state = malloc(sizeof(struct gameState));
    setGameState(state);

    struct gameState *state2;
    state2 = malloc(sizeof(struct gameState));
    *state2 = *state;


    // int cardEffect(int card, int choice1, int choice2, int choice3, struct gameState *state, int handPos, int *bonus)

    enum CARD card = sea_hag;
    int choice1 = 0, choice2 = 0, choice3 = 0;
    int *bonus = 0;
    int handPos = 0;
    insertCard(sea_hag, handPos, state);
    cardEffect(card, choice1, choice2, choice3, state, handPos, bonus);
    mySeaHagCard(handPos, state2);

    // assert (memcmp(state, state2, sizeof(*state)) == 0);
    
    showGameState(state);
    showGameState(state2);


    free(state);
    free(state2);
    //  Free memory from random number generator
    gsl_rng_free(rng);
    return 0;
}